require "lua_ex"
require "lua_ex_utils"
lua_ex.load_lib( "lua_utils.dll" );
utils = lua_ex.create( "utils" );

mgr = edx.document_manager;
mgr.__last_cmd = {};
xws_mgr = edx.xws_mgr;
project_wizard = edx:get_object("project_wizard");
config_debug_run = edx:get_object("dialog:config:debug/run");
toolset_manager = edx:get_object("dialog:config:toolset_manager");
toolset_env_path = edx.make_config_path("toolset.json", 0);
edx_env_path = edx.make_config_path("edx.env", 0);
edx_config_path = edx.config_path;
menu_bar = edx.get_object("menu_bar");

edx.env = {
	main = {
		position = {
			left = 0;
			top = 0;
			width = 800;
			height = 600;
		};
		show = 0;
	};
	recently = {};
	layout = {
		simple = [[<layout><grid vert="true" left="0" top="24" width="1479" height="862"><pane mode="40000000" aitem="0" msize="120" left="0" top="24" width="1479" height="862"><grid vert="false" left="0" top="24" width="1479" height="862"><pane mode="40000000" aitem="0" msize="120" left="0" top="24" width="1479" height="862"><grid vert="true" left="0" top="24" width="1479" height="862"><pane mode="0" aitem="0" msize="280" left="0" top="24" width="1479" height="862"><grid vert="false" left="0" top="24" width="1479" height="862"><pane mode="0" aitem="0" msize="280" left="0" top="24" width="1479" height="862"><grid vert="true" left="0" top="24" width="1479" height="862"><pane mode="40000000" aitem="0" msize="120" left="0" top="24" width="1479" height="862"><grid vert="false" left="0" top="24" width="1479" height="862"><pane mode="0" aitem="0" msize="140" left="0" top="24" width="1479" height="862"><item type="doc frame"/></pane><pane mode="60000000" aitem="0" msize="120" left="0" top="651" width="1479" height="257"><item type="tab frame" minimized="true" pos="1" width="1479" height="257"><tab>output</tab></item></pane></grid></pane></grid></pane></grid></pane></grid></pane></grid></pane></grid></layout>]];
		debug = [[<layout><grid vert="true" left="0" top="24" width="1479" height="884"><pane mode="40000000" aitem="0" msize="120" left="0" top="24" width="1479" height="884"><grid vert="false" left="0" top="24" width="1479" height="884"><pane mode="40000000" aitem="0" msize="120" left="0" top="24" width="1479" height="884"><grid vert="true" left="0" top="24" width="1479" height="884"><pane mode="0" aitem="0" msize="280" left="0" top="24" width="1479" height="884"><grid vert="false" left="0" top="24" width="1479" height="884"><pane mode="0" aitem="0" msize="280" left="0" top="24" width="1479" height="884"><grid vert="true" left="0" top="24" width="1479" height="884"><pane mode="40000000" aitem="0" msize="120" left="0" top="24" width="1479" height="884"><grid vert="false" left="0" top="24" width="1479" height="884"><pane mode="0" aitem="0" msize="140" left="0" top="24" width="1479" height="576"><item type="doc frame"/></pane><pane mode="40000000" aitem="0" msize="120" left="0" top="603" width="1479" height="305"><grid vert="true" left="0" top="603" width="1479" height="305"><pane mode="40000000" aitem="0" msize="120" left="0" top="603" width="818" height="305"><item type="tab frame" minimized="false" pos="11" width="819" height="305"><tab>output</tab><tab>Watch</tab><tab>locals</tab></item></pane><pane mode="40000000" aitem="0" msize="120" left="821" top="603" width="657" height="305"><item type="tab frame" minimized="false" pos="1" width="657" height="305"><tab>threads</tab><tab>modules</tab><tab>stack</tab></item></pane></grid></pane></grid></pane></grid></pane></grid></pane></grid></pane></grid></pane></grid></layout>]];
	};
};
DEFAULT_NOTIFY_TIMEOUT = 3;
SERIAL_BAUDRATES_HI = {
	"57600", "76800", "115200",	"128000",
	"230400", "256000", "384000", "512000",
	"768000", "921600", "1843200", "2048000",
};
SERIAL_BAUDRATES = {
	"300", "600", "1200", "1800",
	"2400", "4800", "7200", "9600",
	"14400", "19200", "25600", "38400",
	"51200", table.unpack(SERIAL_BAUDRATES_HI)
};
SERIAL_DEFAULT_BAUDRATE = "115200";
require "language"
local _current_locale = string.lower(edx.locale);
local _current_lang = (LANGUAGE and (LANGUAGE[_current_locale] or LANGUAGE["default"])) or {};
edx:update_language(_current_lang);

function LANG(text)
	return _current_lang[text] or text;
end;

--[[
doc.content_type is the index of the language configuration in the config.xml
0 is unknown type
makefile	0
c/c++		1
c51			2
javascript	3
opencl		4
xml			5
html		6
vc project	7
bat file	8
lua			9
css			10
d			11
java		12
cmake		13
ini			14
]]

content_type_text = 0;
content_type_cxx = 1;
content_type_c51 = 2;
content_type_js = 3;
content_type_ocl = 4;
content_type_xml = 5;
content_type_html = 6;
content_type_bat = 8;
content_type_lua = 9;
content_type_css = 10;
content_type_dlang = 11;
content_type_java = 12;
content_type_cmake = 13;
content_type_ini = 14;
content_type_sh = 15;
content_type_json = 16;
content_type_md = 17;
content_type_logcat = 18;
content_type_makefile = 19;

-- name matched with LSP language type id
content_type_name = {
	[content_type_cxx] = "cpp";
	[content_type_c51] = "cpp";
	[content_type_dlang] = "d";
	[content_type_js] = "js";
	[content_type_lua] = "lua";
	[content_type_java] = "java";
	[content_type_css] = "css";
	[content_type_cmake] = "cmake";
	[content_type_json] = "json";
	[content_type_xml] = "xml";
	[content_type_html] = "xml";
	[content_type_md] = "markdown";
	[content_type_logcat] = "logcat";
	[content_type_ini] = "ini";
	[content_type_sh] = "shell";
	[content_type_text] = "text";
	[content_type_bat] = "bat";
	[content_type_makefile] = "makefile";
};

function dbg_call( func, err_msg )
	local result = {
		xpcall( func,
			function(msg)
				if err_msg ~= nil then
					print( err_msg );
				end;
				msg = debug.traceback( msg );
				msg = msg:gsub( "\n", "\r\n" );
				print( msg );
				print( "\r\n" );
				return 0;
			end
		)
	};
	if result[1] == true then
		table.remove( result, 1 );
		return table.unpack(result);
	end;
end;

function show_notify(message)
	edx:show_notify(DEFAULT_NOTIFY_TIMEOUT, message);
end;

doc_type = {
	text = 1;
	hex = 2;
};

_op_scope = {
	diff_dialog = -3;
	solution = -2;
	_global = -1;
	none = 0;
	text = 1;
	hex = 2;
};

_op = {
	none = 0;
	enhanced_left = 1;
	enhanced_right = 2;
	enhanced_left_select = 3;
	enhanced_right_select = 4;
	enhanced_home = 5;
	enhanced_home_select = 6;
	cursor_left = 7;
	cursor_right = 8;
	cursor_up = 9;
	cursor_down = 10;
	cursor_end = 11;
	cursor_home = 12;
	cursor_page_up = 13;
	cursor_page_down = 14;
	cursor_top = 15;
	cursor_bottom = 16;
	cursor_left_select = 17;
	cursor_right_select = 18;
	cursor_up_select = 19;
	cursor_down_select = 20;
	cursor_end_select = 21;
	cursor_home_select = 22;
	cursor_page_up_select = 23;
	cursor_page_down_select = 24;
	cursor_top_select = 25;
	cursor_bottom_select = 26;
	insert_mode_switch = 27;
	delete_character = 28;
	backspace_character = 29;
	delete_line = 30;
	unselect = 31;
	indent_insert_line = 32;
	indent_append_line = 33;
	indent_split_line = 34;
	wrap_selection_bracket = 35;
	wrap_selection_square_bracket = 36;
	wrap_selection_parenthesis = 37;
	indent_write_left_bracket = 38;
	indent_write_right_bracket = 39;
	indent_write_left_parenthesis = 40;
	jump_match_bracket = 41;
	jump_match_bracket_select = 42;
	jump_prev_bracket = 43;
	jump_next_bracket = 44;
	select_all = 45;
	select_word = 46;
	format_selection = 47;
	indent_selection = 48;
	unindent_selection = 49;
	save = 50;
	save_as = 51;
	close = 52;
	_open = 53;
	_open_in_current_window = 54;
	new_buffer = 55;
	incremental_search_next = 56;
	incremental_search_prev = 57;
	goto_line = 58;
	goto_file = 59;
	jump_to_file = 60;
	fold_switch = 61;
	fold_all_switch = 62;
	_copy = 63;
	cut = 64;
	paste = 65;
	multi_paste = 66;
	comment_selection = 67;
	uncomment_selection = 68;
	cursor_history_prev = 69;
	cursor_history_next = 70;
	next_buffer = 71;
	prev_buffer = 72;
	exit = 73;
	find = 74;
	find_next = 75;
	undo = 76;
	redo = 77;
	jump_to_definition = 78;
	jump_to_declaration = 79;
	replace = 80;
	find_in_files = 81;
	replace_in_files = 82;
	show_buffer_list = 83;
	indent_write_colon = 84;
	show_completion_list = 85;
	completion_selected = 86;
	completion_typing = 87;
	completion_end_list = 88;
	show_completion_tip = 89;
	completion_end_tip = 90;
	find_next_reverse = 91;
	paste_ex = 92; -- paste and keeps the selection
	center_cursor_line = 93;
	close_solution = 94;

	xws_remove_selected_item = 95;

	completion_selecting = 96;

	cursor_left_select_vertically = 97;
	cursor_right_select_vertically = 98;
	cursor_up_select_vertically = 99;
	cursor_down_select_vertically = 100;

	open_file_dir = 101;
	xws_open_file_dir = 102;
	xws_open_file = 103;
	cmake_rebuild_cache = 104;
	cmake_install = 105;
	cmake_build_cache = 106;
	build_target = 107;
	xws_open_terminal = 108;
	xws_close_opend_file = 109;
	close_other_files = 110;
	open_file_terminal = 112;
	ext_git_open_gui = 113;
	ext_git_open_history = 114;
	ext_git_pull = 115;
	ext_git_push = 116;
	search_everywhere = 117;
	update_completion_tip = 118;
	update_completion_list = 119;
	indent_split_line_or_jump_placeholder = 120;
	find_implementation= 121;
	find_reference = 122;
	cmake_refresh_cache = 123;
	xws_paste_file = 124;
	xws_copy_selected_item = 125;
	xws_cut_selected_item = 126;
	xws_rename_selected_item = 127;
	xws_remove_selected_item_permanently = 128;
	build_project = 129;
	rebuild_project = 130;
	rebuild_target = 131;
	build_and_run = 132;
	stop_build = 133;
	xws_new_file = 134;
	xws_new_folder = 135;
	new_cmake_project = 136;
	open_config_file = 137;
	locate_current_document = 138;
	save_all = 139;
	open_directory = 140;
	open_with_text_editor = 141;
	open_with_hex_editor = 142;
	open_tab_dir = 143;
	open_tab_terminal = 144;
	copy_tab_path = 145;
	close_tab = 146;
	locate_tab_file = 147;
	new_project = 148;
	move_selection_up = 149;
	move_selection_down = 150;
	project_configuration = 151;
	xws_open_text_file = 152;
	xws_open_hex_file = 153;
	
	debug_start = 251;
	debug_terminate = 252;
	debug_step_over = 253;
	debug_step_in = 254;
	debug_step_out = 255;
	debug_toggle_break_point = 256;
	debug_list_break_point = 257;	-- 列举所有断点
	debug_jump_to = 258;
	debug_break = 259;

	git_pull = 301;
	git_push = 302;
	git_commit = 303;
	git_diff = 304;
	git_property = 305;
	git_checkout = 306;
	git_fetch = 307;
	git_configuration = 308;
	git_branch = 309;
	git_merge = 310;
	git_init = 311;
	git_diff_file = 312;
	diff_locate_source = 313;
	diff_locate_source_ex = 314;	-- 定位源代码后不关闭diff dialog
	
	active_pane_first = 0x8000;
	active_pane_last = 0x81FF;
	active_editor = 0x8000;		-- 定位到编辑窗口
	active_output = 0x8001;		-- 定位到输出窗口
	hide_output = 0x8101;		-- 隐藏输出窗口
	active_search_result = 0x800a;	-- 定位到查找窗口
	hide_search_result = 0x810a; 	-- 隐藏查找窗口
	active_locals	= 0x800b;	-- 定位到locals窗口
	hide_locals		= 0x810b;  	-- 隐藏locals窗口
	active_watch 	= 0x800c;	-- 定位到watch窗口
	hide_watch		= 0x810c; 	-- 隐藏watch窗口
	active_threads	= 0x800d;	-- 定位到threads窗口
	hide_threads	= 0x810d; 	-- 隐藏threads窗口
	active_modules	= 0x800e;	-- 定位到modules窗口
	hide_modules	= 0x810e;	-- 隐藏modules窗口
	active_stack	= 0x800f;	-- 定位到call stack窗口
	hide_stack		= 0x810f;	-- 隐藏call stack窗口
	active_solution	= 0x8010;	-- 定位到solution窗口
	hide_solution	= 0x8110;	-- 隐藏solution窗口
	active_class	= 0x8011;	-- 定位到class窗口
	hide_class		= 0x8111;	-- 隐藏class窗口
	active_build	= 0x8012;	-- 定位到Build Result窗口
	hide_build		= 0x8112;	-- 隐藏Build Result窗口
	active_debugger	= 0x8013;	-- 定位到debugger窗口
	hide_debugger	= 0x8113;	-- 隐藏debugger窗口
	active_toolsets	= 0x8015;	-- 列举所有工具链
	active_lsp		= 0x8016;	-- 定位到LSP窗口
	hide_lsp		= 0x8116;	-- 隐藏LSP窗口
	active_structure = 0x8017;	-- 定位到structure窗口
	hide_structure = 0x8117;	-- 隐藏structure窗口
	active_revisions = 0x8018;
	hide_revisions = 0x8118;
	active_registers = 0x8019;
	hide_registers = 0x8119;
	active_serial_ports = 0x801A;
	hide_serial_ports = 0x811A;

	show_about = 0x1200;
	toggle_fullscreen = 0x1100;
	register_shell_menu_shortcuts = 0x1101;
	help = 0x1201;
	help_search = 0x1202;
	open_homepage = 0x1203;
	dump_bin = 0x1204;
	zoom_in = 0x1205;
	zoom_out = 0x1206;
	zoom_reset = 0x1207;
	serial_monitor = 0x1208;
};
	
function edx:active_pane(cmd_id)
	local pane_map = {
		[_op.active_editor] = "editor";
		[_op.active_output] = "output";
		[_op.active_search_result] = "find";
		[_op.active_locals] = "locals";
		[_op.active_watch] = "watch";
		[_op.active_threads] = "threads";
		[_op.active_modules] = "modules";
		[_op.active_registers] = "registers";
		[_op.active_stack] = "stack";
		[_op.active_solution] = "solution";
		[_op.active_class] = "class";
		[_op.active_build] = "build_result";
		[_op.active_debugger] = "debugger";
		[_op.active_lsp] = "lsp";
		[_op.active_structure] = "structure";
		[_op.active_serial_ports] = "serial_ports";
		[_op.active_revisions] = "revisions";
	};
	local show_base = _op.active_pane_first;
	local hide_base = _op.active_pane_first + 0x100;
	if cmd_id >= hide_base then
		self:hide(pane_map[cmd_id - hide_base + show_base]);
	else
		self:active(pane_map[cmd_id]);
	end;
end;

local __dynamic_menu_id_base = 0xF100;
local function GEN_ID_BASE(num)
	local base = __dynamic_menu_id_base;
	if num%0x20 then
		num = num + 0x20 - (num%0x20);
	end;
	__dynamic_menu_id_base = __dynamic_menu_id_base + num;
	return base;
end;

RECENTLY_ITEM_ID_BASE = GEN_ID_BASE(32);
RECENTLY_FOLDER_ID_BASE = GEN_ID_BASE(32);
SYNTAX_MENU_ID_BASE = GEN_ID_BASE(32);
LINE_FORMAT_MENU_ID_BASE = GEN_ID_BASE(32);
CMAKE_CONFIG_ID_BASE = GEN_ID_BASE(32);
CMAKE_TOOLSET_ID_BASE = GEN_ID_BASE(32);
CMAKE_SERIAL_PORTS_ID_BASE = GEN_ID_BASE(32);
CMAKE_SERIAL_BUAD_ID_BASE = GEN_ID_BASE(64);
CMAKE_CPU_TYPES_ID_BASE = GEN_ID_BASE(32);
CMAKE_BOARD_TYPES_ID_BASE = GEN_ID_BASE(32);
CMAKE_DEBUG_ADAPTERS_ID_BASE = GEN_ID_BASE(32);
CMAKE_FMT_ID_BASE = GEN_ID_BASE(32);
CMAKE_TARGETS_ID_BASE = GEN_ID_BASE(512);

short_cuts = {
	[_op.next_buffer] = {{ k("ctrl+tab"), _op_scope._global }};
	[_op.prev_buffer] = {{ k("ctrl+shift+tab"), _op_scope._global }};
	[_op.new_buffer] = {{ k("ctrl+n"), _op_scope._global }};
	[_op._open] = {{ k("ctrl+o"), _op_scope._global }};
	[_op.open_directory] = {{ k("alt+o"), _op_scope._global }};
	[_op._open_in_current_window] = {{ k("ctrl+shift+o"), _op_scope._global }};
	[_op.close] = {{ k("ctrl+f4"), _op_scope._global }};
	[_op.save] = {{ k("ctrl+s"), _op_scope._global }};
	[_op.save_as] = {{ k("ctrl+shift+s"), _op_scope._global }};
	[_op.save_all] = {{ k("ctrl+shift+a"), _op_scope._global }};
	[_op.exit] = {{ k("alt+q"), _op_scope._global }};
	[_op.build_project] = {{ k("ctrl+shift+b"), _op_scope._global }};
	[_op.build_and_run] = {{ k("ctrl+f5"), _op_scope._global }};
	[_op.rebuild_project] = {{ k("ctrl+alt+f7"), _op_scope._global }};
	[_op.build_target] = {{ k("ctrl+b"), _op_scope._global }};
	[_op.stop_build] = {{ k("ctrl+break"), _op_scope._global }};

	[_op.redo] = {{ k("ctrl+y"), _op_scope.text }, { k("ctrl+y"), _op_scope.hex }};
	[_op.undo] = {{ k("ctrl+z"), _op_scope.text }, { k("ctrl+z"), _op_scope.hex }};
	[_op.cut] = {{ k("ctrl+x"), _op_scope.text }, { k("ctrl+x"), _op_scope.hex }};
	[_op._copy] = {{ k("ctrl+c"), _op_scope.text }, { k("ctrl+c"), _op_scope.hex }};
	[_op.paste] = {{ k("ctrl+v"), _op_scope.text }, {k("ctrl+v"), _op_scope.hex }};
	[_op.multi_paste] = {{ k("ctrl+shift+v"), _op_scope.text }};
	[_op.delete_character] = {{ k("delete"), _op_scope.text }, { k("delete"), _op_scope.hex }};
	[_op.select_all] = {{ k("ctrl+a"), _op_scope.text },{ k("ctrl+a"), _op_scope.hex }};

	[_op.incremental_search_next] = {{ k("ctrl+i"), _op_scope.text }};
	[_op.incremental_search_prev] = {{ k("ctrl+shift+i"), _op_scope.text }};
	
	[_op.find] = {{ k("ctrl+f"), _op_scope.text }};
	[_op.find_in_files] = {{ k("ctrl+shift+f"), _op_scope.text }};
	[_op.find_next_reverse] = {{ k("shift+f3"), _op_scope.text }};
	[_op.find_next] = {{ k("f3"), _op_scope.text }};
	[_op.goto_line] = {{ k("ctrl+g"), _op_scope.text}, { k("ctrl+g"), _op_scope.hex}};
	[_op.cursor_history_prev] = {{ k("ctrl+-"), _op_scope.text }};
	[_op.cursor_history_next] = {{ k("ctrl+shift+-"), _op_scope.text }};
	[_op.jump_match_bracket] = {{ k("ctrl+}"), _op_scope.text }};
	[_op.jump_match_bracket_select] = {{ k("ctrl+shift+}"), _op_scope.text }};

	[_op.jump_to_file] = {{ k("ctrl+shift+g"), _op_scope.text }};
	[_op.jump_to_definition] = {{ k("f12"), _op_scope.text }};
	[_op.find_implementation] = {{ k("alt+f12"), _op_scope.text }};
	[_op.find_reference] = {{ k("shift+f12"), _op_scope.text }};
	[_op.move_selection_up] = {{ k("alt+up"), _op_scope.text }};
	[_op.move_selection_down] = {{ k("alt+down"), _op_scope.text }};

	[_op.fold_switch] = {{ k("ctrl+m"), k("m"), _op_scope.text },{ k("ctrl+m"), k("ctrl+m"), _op_scope.text }};
	[_op.fold_all_switch] = {{ k("ctrl+m"), k("l"), _op_scope.text },{ k("ctrl+m"), k("ctrl+l"), _op_scope.text }};
	
	[_op.comment_selection] = {{ k("ctrl+k"), k("c"), _op_scope.text },{ k("ctrl+k"), k("ctrl+c"), _op_scope.text }};
	[_op.uncomment_selection] = {{ k("ctrl+k"), k("u"), _op_scope.text },{ k("ctrl+k"), k("ctrl+u"), _op_scope.text }};
	[_op.format_selection] = {{ k("ctrl+k"), k("f"), _op_scope.text },{ k("ctrl+k"), k("ctrl+f"), _op_scope.text }};

	[_op.wrap_selection_parenthesis] = {{ k("ctrl+shift+alt+("), _op_scope.text }};
	[_op.wrap_selection_bracket] = {{ k("ctrl+shift+alt+{"), _op_scope.text }};
	[_op.wrap_selection_square_bracket] = {{ k("ctrl+alt+{"), _op_scope.text }};

	[_op.enhanced_left] = {{ k("ctrl+left"), _op_scope.text }, { k("ctrl+left"), _op_scope.hex }};
	[_op.enhanced_right] = {{ k("ctrl+right"), _op_scope.text }, { k("ctrl+right"), _op_scope.hex }};
	[_op.enhanced_left_select] = {{ k("ctrl+shift+left"), _op_scope.text }, { k("ctrl+shift+left"), _op_scope.hex }};
	[_op.enhanced_right_select] = {{ k("ctrl+shift+right"), _op_scope.text }, { k("ctrl+shift+right"), _op_scope.hex }};

	[_op.cursor_left] = {{ k("left"), _op_scope.text }, { k("left"), _op_scope.hex }};
	[_op.cursor_right] = {{ k("right"), _op_scope.text }, { k("right"), _op_scope.hex }};
	[_op.cursor_down] = {{ k("down"), _op_scope.text }, { k("down"), _op_scope.hex }};
	[_op.cursor_up] = {{ k("up"), _op_scope.text }, { k("up"), _op_scope.hex }};
	[_op.enhanced_home] = {{ k("home"), _op_scope.text }, { k("home"), _op_scope.hex }};
	[_op.cursor_end] = {{ k("end"), _op_scope.text }, { k("end"), _op_scope.hex }};
	[_op.cursor_page_up] = {{ k("pageup"), _op_scope.text }, { k("pageup"), _op_scope.hex }};
	[_op.cursor_page_down] = {{ k("pagedown"), _op_scope.text }, { k("pagedown"), _op_scope.hex }};
	[_op.cursor_top] = {{ k("ctrl+home"), _op_scope.text }, { k("ctrl+home"), _op_scope.hex }};
	[_op.cursor_bottom] = {{ k("ctrl+end"), _op_scope.text }, { k("ctrl+end"), _op_scope.hex }};
	[_op.cursor_left_select] = {{ k("shift+left"), _op_scope.text }, { k("shift+left"), _op_scope.hex }};
	[_op.cursor_right_select] = {{ k("shift+right"), _op_scope.text }, { k("shift+right"), _op_scope.hex }};
	[_op.cursor_down_select] = {{ k("shift+down"), _op_scope.text }, { k("shift+down"), _op_scope.hex }};
	[_op.cursor_up_select] = {{ k("shift+up"), _op_scope.text }, { k("shift+up"), _op_scope.hex }};

	[_op.cursor_left_select_vertically] = {{ k("alt+shift+left"), _op_scope.text }};
	[_op.cursor_right_select_vertically] = {{ k("alt+shift+right"), _op_scope.text }};
	[_op.cursor_down_select_vertically] = {{ k("alt+shift+down"), _op_scope.text }};
	[_op.cursor_up_select_vertically] = {{ k("alt+shift+up"), _op_scope.text }};
	
	[_op.enhanced_home_select] = {{ k("shift+home"), _op_scope.text }, { k("shift+home"), _op_scope.hex }};
	[_op.cursor_end_select] = {{ k("shift+end"), _op_scope.text }, { k("shift+end"), _op_scope.hex }};
	[_op.cursor_page_up_select] = {{ k("shift+pageup"), _op_scope.text }, { k("shift+pageup"), _op_scope.hex }};
	[_op.cursor_page_down_select] = {{ k("shift+pagedown"), _op_scope.text }, { k("shift+pagedown"), _op_scope.hex }};
	[_op.cursor_top_select] = {{ k("ctrl+shift+home"), _op_scope.text }, { k("ctrl+shift+home"), _op_scope.hex }};
	[_op.cursor_bottom_select] = {{ k("ctrl+shift+end"), _op_scope.text }, { k("ctrl+shift+end"), _op_scope.hex }};
	[_op.insert_mode_switch] = {{ k("insert"), _op_scope.text }, { k("insert"), _op_scope.hex }};
	[_op.delete_character] = {{ k("del"), _op_scope.text }, { k("del"), _op_scope.hex }};
	[_op.backspace_character] = {{ k("backspace"), _op_scope.text }, { k("backspace"), _op_scope.hex }};
	[_op.delete_line] = {{ k("shift+del"), _op_scope.text }};
	[_op.unselect] = {{ k("escape"), _op_scope.text }, { k("escape"), _op_scope.hex }};
	[_op.indent_insert_line] = {{ k("ctrl+enter"), _op_scope.text }};
	[_op.indent_append_line] = {{ k("ctrl+shift+enter"), _op_scope.text }};
	[_op.indent_split_line_or_jump_placeholder] = {{ k("enter"), _op_scope.text }};
	[_op.indent_write_right_bracket] = {{ k("shift+}"), _op_scope.text }};
	[_op.indent_write_left_bracket] = {{ k("shift+{"), _op_scope.text }};
	[_op.indent_write_left_parenthesis] = {{ k("shift+("), _op_scope.text }};
	[_op.indent_write_colon] = {{ k("shift+;"), _op_scope.text }};
	[_op.indent_selection] = {{ k("tab"), _op_scope.text }};
	[_op.unindent_selection] = {{ k("shift+tab"), _op_scope.text }, { k("shift+tab"), _op_scope.hex }};
	[_op.select_word] = {{ k("ctrl+w"), _op_scope.text }};
	[_op.show_completion_list] = {{ k("alt+."), _op_scope.text }};
	[_op.show_completion_tip] = {{ k("alt+,"), _op_scope.text }};
	[_op.toggle_fullscreen] = {{ k("alt+shift+enter"), _op_scope._global }};
	[_op.help] = {{ k("f1"), _op_scope.text }};
	[_op.help_search] = {{ k("alt+f1"), _op_scope.text }};

	[_op.xws_paste_file] = {{ k("ctrl+v"), _op_scope.solution }};
	[_op.xws_copy_selected_item] = {{ k("ctrl+c"), _op_scope.solution }};
	[_op.xws_cut_selected_item] = {{ k("ctrl+x"), _op_scope.solution }};
	[_op.xws_rename_selected_item] = {{ k("f2"), _op_scope.solution }};
	[_op.xws_remove_selected_item] = {{ k("delete"), _op_scope.solution }};
	[_op.xws_remove_selected_item_permanently] = {{ k("shift+delete"), _op_scope.solution }};
	[_op.project_configuration] = {{ k("alt+enter"), _op_scope.solution }};
	
	[_op.debug_start] = {{ k("f5"), _op_scope._global }};
	[_op.debug_terminate] = {{ k("shift+f5"), _op_scope._global }};
	[_op.debug_break] = {{ k("ctrl+f9"), _op_scope._global }};
	[_op.debug_step_over] = {{ k("f10"), _op_scope._global }};
	[_op.debug_step_in] = {{ k("f11"), _op_scope._global }};
	[_op.debug_step_out] = {{ k("shift+f11"), _op_scope._global }};
	[_op.debug_jump_to] = {{ k("alt+f9"), _op_scope._global }};
	[_op.debug_toggle_break_point] = {{ k("f9"), _op_scope._global }};
	[_op.debug_list_break_point] = {{ k("ctrl+alt+b"), _op_scope._global }};

	[_op.locate_current_document] = {{ k("alt+l"), _op_scope._global }};
	[_op.locate_tab_file] = {{ k("alt+l"), _op_scope.none }};

	[_op.active_editor] 		= {{ k("escape"), _op_scope._global }};
	[_op.active_output] 		= {{ k("ctrl+alt+o"), _op_scope._global }};
	[_op.hide_output] 			= {{ k("ctrl+alt+shift+o"), _op_scope._global }};
	[_op.active_search_result]	= {{ k("ctrl+alt+f"), _op_scope._global }};
	[_op.hide_search_result]	= {{ k("ctrl+alt+shift+f"), _op_scope._global }}; 
	[_op.active_locals]			= {{ k("ctrl+alt+a"), _op_scope._global }};
	[_op.hide_locals]			= {{ k("ctrl+alt+shift+a"), _op_scope._global }};
	[_op.active_watch] 			= {{ k("ctrl+alt+w"), _op_scope._global }};
	[_op.hide_watch]			= {{ k("ctrl+alt+shift+w"), _op_scope._global }}; 
	[_op.active_threads]		= {{ k("ctrl+alt+s"), _op_scope._global }};
	[_op.hide_threads]			= {{ k("ctrl+alt+shift+s"), _op_scope._global }}; 
	[_op.active_modules]		= {{ k("ctrl+alt+m"), _op_scope._global }};
	[_op.hide_modules]			= {{ k("ctrl+alt+shift+m"), _op_scope._global }};
	[_op.active_registers]		= {{ k("ctrl+alt+r"), _op_scope._global }};
	[_op.hide_registers]		= {{ k("ctrl+alt+shift+r"), _op_scope._global }};
	[_op.active_stack]			= {{ k("ctrl+alt+c"), _op_scope._global }};
	[_op.hide_stack]			= {{ k("ctrl+alt+shift+c"), _op_scope._global }};
	[_op.active_solution]		= {{ k("ctrl+alt+l"), _op_scope._global }};
	[_op.hide_solution]			= {{ k("ctrl+alt+shift+l"), _op_scope._global }};
	[_op.active_class]			= {{ k("ctrl+alt+e"), _op_scope._global }};
	[_op.hide_class]			= {{ k("ctrl+alt+shift+e"), _op_scope._global }};
	[_op.active_build]			= {{ k("ctrl+alt+k"), _op_scope._global }};
	[_op.hide_build]			= {{ k("ctrl+alt+shift+k"), _op_scope._global }};
	[_op.active_debugger]		= {{ k("ctrl+alt+d"), _op_scope._global }};
	[_op.hide_debugger]			= {{ k("ctrl+alt+shift+d"), _op_scope._global }};
	[_op.active_revisions]		= {{ k("ctrl+alt+h"), _op_scope._global }};
	[_op.hide_revisions]		= {{ k("ctrl+alt+shift+h"), _op_scope._global }};
	[_op.active_toolsets]		= {{ k("ctrl+alt+t"), _op_scope._global }};
	[_op.active_structure]		= {{ k("ctrl+p"), k("h"), _op_scope._global }};
	[_op.hide_structure]		= {{ k("ctrl+shift+p"), k("h"), _op_scope._global }};
	[_op.active_lsp]			= {{ k("ctrl+p"), k("l"), _op_scope._global }};
	[_op.hide_lsp]				= {{ k("ctrl+shift+p"), k("l"), _op_scope._global }};
	[_op.active_serial_ports]	= {{ k("ctrl+p"), k("s"), _op_scope._global }};
	[_op.hide_serial_ports]		= {{ k("ctrl+shift+p"), k("s"), _op_scope._global }};

	[_op.git_diff_file] = {{ k("ctrl+d"), _op_scope.solution }};
	[_op.diff_locate_source] = {{ k("f4"), _op_scope.diff_dialog }};
	[_op.diff_locate_source_ex] = {{ k("ctrl+f4"), _op_scope.diff_dialog }};

	[_op.dump_bin] = {{ k("shift+f12"), _op_scope.hex }};
	
	[_op.zoom_in] = {{ k("ctrl+alt++"), _op_scope._global }};
	[_op.zoom_out] = {{ k("ctrl+alt+-"), _op_scope._global }};
	[_op.zoom_reset] = {{ k("ctrl+alt+0"), _op_scope._global }};
};

function register_short_cuts()
	for _op_code, v in pairs(short_cuts) do
		for idx, sc in ipairs(v) do
			if sc ~= nil then
				local _sc = { _op_code, table.unpack(sc) };
				local sc_ope = table.remove( _sc );
				edx.register_short_cuts( sc_ope, _sc );
			end;
		end;
	end;
end;

local _popup_menu = {
	{ "text/popup/jump_to_file", 0, _op.jump_to_file };
	{ "text/popup/jump_to_definition", 0, _op.jump_to_definition };
	{ "text/popup/find_implementation", 0, _op.find_implementation };
	{ "text/popup/find_reference", 0, _op.find_reference };
	{ nil, 0, 0 },
	{ "text/popup/close_other_files", 0, _op.close_other_files };
	{ "text/popup/open_directory", icon("folder"), _op.open_file_dir };
	{ "text/popup/open_terminal", icon("terminal"), _op.open_file_terminal };
	{ nil, 0, 0 },
	{ "text/popup/cut", icon("cut"), _op.cut };
	{ "text/popup/copy", icon("copy"), _op._copy };
	{ "text/popup/paste", icon("paste"), _op.paste };
	{ nil, 0, 0 },
	{ "text/popup/select_all", 0, _op.select_all };
};

local _syntax_menu = {
	{ "Text", 0, SYNTAX_MENU_ID_BASE + content_type_text };
	{ "C/C++", 0, SYNTAX_MENU_ID_BASE + content_type_cxx };
	{ "CMake", 0, SYNTAX_MENU_ID_BASE + content_type_cmake };
	{ "CSS", 0, SYNTAX_MENU_ID_BASE + content_type_css };
	{ "Dlang", 0, SYNTAX_MENU_ID_BASE + content_type_dlang };
	{ "HTML", 0, SYNTAX_MENU_ID_BASE + content_type_html };
	{ "Ini", 0, SYNTAX_MENU_ID_BASE + content_type_ini };
	{ "Java", 0, SYNTAX_MENU_ID_BASE + content_type_java };
	{ "JavaScript", 0, SYNTAX_MENU_ID_BASE + content_type_js };
	{ "Json", 0, SYNTAX_MENU_ID_BASE + content_type_json };
	{ "Logcat", 0, SYNTAX_MENU_ID_BASE + content_type_logcat };
	{ "Lua", 0, SYNTAX_MENU_ID_BASE + content_type_lua };
	{ "Makefile", 0, SYNTAX_MENU_ID_BASE + content_type_makefile };
	{ "MarkDown", 0, SYNTAX_MENU_ID_BASE + content_type_md };
	{ "XML", 0, SYNTAX_MENU_ID_BASE + content_type_xml };
	{ "OpenCL", 0, SYNTAX_MENU_ID_BASE + content_type_ocl };
	-- { "Output", 0, SYNTAX_MENU_ID_BASE + 11 };
	-- { "Golang", 0, SYNTAX_MENU_ID_BASE + 1 };
	-- { "Rust", 0, SYNTAX_MENU_ID_BASE + 1 };
	-- { "Python", 0, SYNTAX_MENU_ID_BASE + 1 };
	-- { "Yaml", 0, SYNTAX_MENU_ID_BASE + 1 };
	-- { "Ruby", 0, SYNTAX_MENU_ID_BASE + 1 };
};

local _line_format_menu = {
	{ "CR(MAC)", 0, LINE_FORMAT_MENU_ID_BASE + 1 };
	{ "LF(Linux)", 0, LINE_FORMAT_MENU_ID_BASE + 2 };
	{ "CRLF(Win)", 0, LINE_FORMAT_MENU_ID_BASE + 3 };
};

local _tab_menu = {
	{ "text/popup/close_document", 0, _op.close_tab };
	{ nil, 0, 0 },
	{ "text/popup/locate_file", 0, _op.locate_tab_file };
	{ "text/popup/copy_path", icon("copy"), _op.copy_tab_path };
	{ nil, 0, 0 },
	{ "text/popup/open_directory", icon("folder"), _op.open_tab_dir };
	{ "text/popup/open_terminal", icon("terminal"), _op.open_tab_terminal };
};

local _format_menu = {
	{ "utils/file_format_popup/reload_as", 0,
		sub_menu = {
			{ "AUTO", 0, CMAKE_FMT_ID_BASE + 0x00};
			{ "ANSI(with ACP)", 0, CMAKE_FMT_ID_BASE + 0x01};
			{ "UTF-8", 0, CMAKE_FMT_ID_BASE + 0x02};
			{ "UTF-8 with BOM", 0, CMAKE_FMT_ID_BASE + 0x03};
			{ "UTF-16 Little-Endian", 0, CMAKE_FMT_ID_BASE + 0x04};
			{ "UTF-16 Little-Endian with BOM", 0, CMAKE_FMT_ID_BASE + 0x05};
			{ "UTF-16 Big-Endian", 0, CMAKE_FMT_ID_BASE + 0x06};
			{ "UTF-16 Big-Endian with BOM", 0, CMAKE_FMT_ID_BASE + 0x07};
			{ "CP432", 0, CMAKE_FMT_ID_BASE + 0x08};
			{ "CP936", 0, CMAKE_FMT_ID_BASE + 0x09};
		};
	};
	{ "utils/file_format_popup/save_as", 0,
		sub_menu = {
			{ "ANSI(with ACP)", 0, CMAKE_FMT_ID_BASE + 0x11};
			{ "UTF-8", 0, CMAKE_FMT_ID_BASE + 0x12};
			{ "UTF-8 with BOM", 0, CMAKE_FMT_ID_BASE + 0x13};
			{ "UTF-16 Little-Endian", 0, CMAKE_FMT_ID_BASE + 0x14};
			{ "UTF-16 Little-Endian with BOM", 0, CMAKE_FMT_ID_BASE + 0x15};
			{ "UTF-16 Big-Endian", 0, CMAKE_FMT_ID_BASE + 0x16};
			{ "UTF-16 Big-Endian with BOM", 0, CMAKE_FMT_ID_BASE + 0x17};
			{ "CP432", 0, CMAKE_FMT_ID_BASE + 0x18};
			{ "CP936", 0, CMAKE_FMT_ID_BASE + 0x19};
		};
	};
};

local _solution_menu = {
	{ "sln/popup/open", icon( "_open" ), _op.xws_open_file,
		sub_menu = {
			{ "menu_bar/file/open_text", icon("open text"), _op.xws_open_text_file },
			{ "menu_bar/file/open_hex", icon("open hex"), _op.xws_open_hex_file },
		},
		always_send_command = true,
	};
	{ "sln/popup/new", 0,
		sub_menu = {
			{ "sln/popup/new/file", 0, _op.xws_new_file };
			{ "sln/popup/new/folder", 0, _op.xws_new_folder };
		};
	};
	{ nil, 0, 0 },
	{ "sln/popup/open_file_dir", icon("folder"), _op.xws_open_file_dir };
	{ "sln/popup/open_terminal", icon("terminal"), _op.xws_open_terminal };
	{ "sln/popup/close_files_in_dir", 0, _op.xws_close_opend_file };
	{ nil, 0, 0 },
	{ "sln/popup/git", 0,
		sub_menu = {
			{ "git/popup/commit", 0, _op.git_commit };
			{ "git/popup/diff", 0, _op.git_diff_file };
			{ nil, 0, 0 };
			{ "git/popup/pull", 0, _op.git_pull };
			{ "git/popup/push", 0, _op.git_push };
			{ "git/popup/fetch", 0, _op.git_fetch };
			{ nil, 0, 0 };
			{ "git/popup/history", 0, _op.ext_git_open_history };
			{ "git/popup/gui", 0, _op.ext_git_open_gui };
		};
	},
	{ nil, 0, 0 },
	{ "sln/popup/delete", icon("delete"), _op.xws_remove_selected_item };
	{ "sln/popup/cut", icon("cut"), _op.xws_cut_selected_item };
	{ "sln/popup/copy", icon("copy"), _op.xws_copy_selected_item };
	{ "sln/popup/paste", icon("paste"), _op.xws_paste_file };
	{ nil, 0, 0 },
	{ "sln/popup/rename", 0, _op.xws_rename_selected_item };
	{ nil, 0, 0 },
	{ "git/popup/configuration", 0, _op.project_configuration };
	-- { "sln/popup/property", 0, 0 };
};

local _git_menu = {
	{ "git/popup/init", 0, _op.git_init };
	{ "git/popup/diff", 0, _op.git_diff };
	{ "git/popup/commit", 0, _op.git_commit };
	{ nil, 0, 0 },
	{ "git/popup/pull", 0, _op.git_pull };
	{ "git/popup/push", 0, _op.git_push };
	{ "git/popup/checkout", 0, _op.git_checkout };
	{ "git/popup/fetch", 0, _op.git_fetch };
	{ nil, 0, 0 },
	{ "git/popup/history", 0, _op.ext_git_open_history };
	{ "git/popup/gui", 0, _op.ext_git_open_gui };
	{ nil, 0, 0 };
	{ "git/popup/configuration", 0, _op.git_configuration };
};

local _menu_bar = {
	{ "menu_bar/file", 0x8000001,
		sub_menu = {
			{ "menu_bar/file/new_file", icon("new file"), _op.new_buffer,
				sub_menu = {
					{"menu_bar/file/new_file/file", icon("file"), _op.new_buffer},
					{ nil, 0, 0 },
					{"menu_bar/file/new_file/project", icon("solution"), _op.new_project},
				},
				always_send_command = true,
			},
			{ "menu_bar/file/open", icon("open"), _op._open,
				sub_menu = {
					{ "menu_bar/file/open_text", icon("open text"), _op.open_with_text_editor },
					{ "menu_bar/file/open_hex", icon("open hex"), _op.open_with_hex_editor },
				},
				always_send_command = true,
			},
			{ "menu_bar/file/open_directory", icon("_open"), _op.open_directory },
			{ "menu_bar/file/open_in_current_buffer", 0, _op._open_in_current_window },
			{ "menu_bar/file/close_file", icon("close"), _op.close },
			{ "menu_bar/file/close_project", 0, _op.close_solution, true, false },
			{ nil, 0, 0 },
			{ "menu_bar/file/save", icon("save"), _op.save },
			{ "menu_bar/file/save_as", 0, _op.save_as },
			{ nil, 0, 0 },
			{ "menu_bar/file/save_all", icon("save"), _op.save_all },
			{ nil, 0, 0x8000000 },
			{ "menu_bar/file/open_config_file", 0, _op.open_config_file },
			{ nil, 0, 0 },
			{ "menu_bar/file/exit", icon("exit"), _op.exit },
		}
	};
	{ "menu_bar/edit", 0x8000002,
		sub_menu = {
			{ "menu_bar/edit/undo", icon("undo"), _op.undo },
			{ "menu_bar/edit/redo", icon("redo"), _op.redo },
			{ nil, 0, 0 },
			{ "menu_bar/edit/cut", icon("cut"), _op.cut },
			{ "menu_bar/edit/copy", icon("copy"), _op._copy },
			{ "menu_bar/edit/paste", icon("paste"), _op.paste },
			{ "menu_bar/edit/circulate_paste", 0, _op.multi_paste },
			{ "menu_bar/edit/delete", icon("delete"), _op.delete_character },
			{ "menu_bar/edit/select_all", 0, _op.select_all },
			{ nil, 0, 0 },
			{ "menu_bar/edit/find", 0, 0x8100002, true, 
				sub_menu = {
					{ "menu_bar/edit/find/incremental", 0, _op.incremental_search_next },
					{ "menu_bar/edit/find/find_and_replace", icon("find"), _op.find },
					{ "menu_bar/edit/find/find_in_files", icon("find in files"), _op.find_in_files}
				}
			},
			{ "menu_bar/edit/jump_to", 0, 0x8200002, true, 
				sub_menu = {
					{ "menu_bar/edit/jump_to/line", 0, _op.goto_line },
					{ "menu_bar/edit/jump_to/previous_location", icon("previous"), _op.cursor_history_prev },
					{ "menu_bar/edit/jump_to/next_location", icon("next"), _op.cursor_history_next },
					{ "menu_bar/edit/jump_to/matched_brackets", 0, _op.jump_match_bracket },
					{ nil, 0, 0 },
					{ "menu_bar/edit/jump_to/file", 0, _op.jump_to_file },
					{ "menu_bar/edit/jump_to/definition", 0, _op.jump_to_definition },
					{ "menu_bar/edit/jump_to/implementation", 0, _op.find_implementation },
					{ "menu_bar/edit/jump_to/reference", 0, _op.find_reference },
				}
			},
			{ "menu_bar/edit/outline", 0, 0x8300002, true, 
				sub_menu = {
					{ "menu_bar/edit/outline/fold_unfold", 0, _op.fold_switch },
					{ "menu_bar/edit/outline/fold_unfold_all", 0, _op.fold_all_switch },
				}
			},
			{ "menu_bar/edit/advanced", 0, 0x8400002, true, 
				sub_menu = {
					{ "menu_bar/edit/advanced/comment_selection", 0, _op.comment_selection };
					{ "menu_bar/edit/advanced/uncomment_selection", 0, _op.uncomment_selection };
					{ "menu_bar/edit/advanced/format_selection", 0, _op.format_selection };
					{ "menu_bar/edit/advanced/wrap_selection_with_parenthesis", 0, _op.wrap_selection_parenthesis };
					{ "menu_bar/edit/advanced/wrap_selection_with_brackets", 0, _op.wrap_selection_bracket };
					{ "menu_bar/edit/advanced/wrap_selection_with_squire_brackets", 0, _op.wrap_selection_square_bracket };
				}
			},
			{ "menu_bar/edit/zoom", 0, 0x8500002, true,
				sub_menu = {
					{ "menu_bar/edit/zoom/zoom_in", 0, _op.zoom_in };
					{ "menu_bar/edit/zoom/zoom_out", 0, _op.zoom_out };
					{ "menu_bar/edit/zoom/zoom_0", 0, _op.zoom_reset };
				}
			}
		};
	};
	{
		"menu_bar/project", 0x8000003, false,
	};
	{
		"menu_bar/cmake", 0xA000001, false,
		sub_menu = {
			{ "menu_bar/cmake/build_all", icon("build"), _op.build_project },
			{ "menu_bar/cmake/build", icon("build one"), _op.build_target },
			{ "menu_bar/cmake/install", 0, _op.cmake_install},
			-- { "menu_bar/cmake/serial_monitor", 0, _op.serial_monitor, false},
			{ nil, 0, 0 },
			{ "menu_bar/cmake/rebuild_all", icon("build"), _op.rebuild_project },
			{ "menu_bar/cmake/rebuild", icon("build one"), _op.rebuild_target },
			{ nil, 0, 0 },
			{ "menu_bar/cmake/refresh_cmake_cache", 0, _op.cmake_refresh_cache },
			{ "menu_bar/cmake/rebuild_cmake_cache", 0, _op.cmake_rebuild_cache },
			{ nil, 0, 0 },
			{ "menu_bar/cmake/configuration", icon("config"), 0xA100001, true, sub_menu = {}; },
			{ "menu_bar/cmake/toolsets", icon("toolset"), 0xA100002, true, sub_menu = {}; },
			{ "menu_bar/cmake/targets", icon("tasks"), 0xA100003, true, sub_menu = {}; },
			{ "menu_bar/cmake/serial_ports", 0, 0xA100004, false, sub_menu = {};},
			{ "menu_bar/cmake/serial_baud", 0, 0xA100008, false, sub_menu = {};},
			{ "menu_bar/cmake/cpus", 0, 0xA100005, false, sub_menu = {};},
			{ "menu_bar/cmake/boards", 0, 0xA100006, false, sub_menu = {};},
			{ "menu_bar/cmake/debug_adapters", 0, 0xA100007, false, sub_menu = {};},
		}
	};
	{
		"menu_bar/debug", 0xB000001, false,
		sub_menu = {
			{ "menu_bar/debug/build_and_run", 0, _op.build_and_run },
			{ "menu_bar/debug/start_debug", 0, _op.debug_start },
			{ "menu_bar/debug/terminate", 0, _op.debug_terminate },
			{ "menu_bar/cmake/break", 0, _op.debug_break },
			{ nil, 0, 0 },
			{ "menu_bar/cmake/step_over", 0, _op.debug_step_over},
			{ "menu_bar/cmake/step_in", 0, _op.debug_step_in },
			{ "menu_bar/cmake/step_out", 0, _op.debug_step_out },
			{ "menu_bar/cmake/jump_to", 0, _op.debug_jump_to },
			{ nil, 0, 0 },
			{ "menu_bar/cmake/toggle_break_point", 0, _op.debug_toggle_break_point },
			{ "menu_bar/cmake/list_break_point", 0, _op.debug_list_break_point },
		}
	};
	{ "menu_bar/window", 0x8000004, 
		sub_menu = {
			{ "menu_bar/window/panes", 0, 0x8100004, true,
				sub_menu = {
					{ "menu_bar/window/open/solution", icon("solution"), _op.active_solution},
					-- { "menu_bar/window/open/class", 0, _op.active_class, false},
					{ nil, 0, 0 },
					{ "menu_bar/window/open/output", icon("output"), _op.active_output},
					{ "menu_bar/window/open/search_result", icon("find result"), _op.active_search_result},
					{ "menu_bar/window/open/build", icon("build_result"), _op.active_build},
					{ "menu_bar/window/open/lsp", icon("lsp"), _op.active_lsp},
					{ nil, 0, 0 },
					{ "menu_bar/window/open/debugger", icon("debugger"), _op.active_debugger},
					{ "menu_bar/window/open/locals", icon("locals"), _op.active_locals},
					{ "menu_bar/window/open/watch", icon("watch"), _op.active_watch},
					{ "menu_bar/window/open/registers", icon("registers"), _op.active_registers},
					{ "menu_bar/window/open/stack", icon("stack"), _op.active_stack},
					{ "menu_bar/window/open/threads", icon("threads"), _op.active_threads},
					{ "menu_bar/window/open/modules", icon("modules"), _op.active_modules},
					{ "menu_bar/window/open/structure", icon("structure"), _op.active_structure},
					{ "menu_bar/window/open/serial_ports", icon("serial_ports"), _op.active_serial_ports},
					{ nil, 0, 0 },
					{ "menu_bar/window/open/breakpoints", icon("breakpoints"), _op.debug_list_break_point},
					{ "menu_bar/window/open/toolsets", icon("toolsets"), _op.active_toolsets},
					{ nil, 0, 0 },
					{ "menu_bar/window/open/revisions", icon("revisions"), _op.active_revisions},
				};
			};
			{ "menu_bar/window/next_file", 0, _op.next_buffer };
			{ "menu_bar/window/previous_file", 0, _op.prev_buffer };
			-- { "menu_bar/window/file_list", 0, 0, false };
			{ nil, 0, 0 },
			{ "menu_bar/window/fullscreen", 0, _op.toggle_fullscreen };
		}
	};

	{ "menu_bar/help", 0x8888888, 
		sub_menu = {
			{ "menu_bar/help/help", 0, _op.help };
			{ "menu_bar/help/find", 0, _op.help_search };
			{ nil, 0, 0 },
			{ "menu_bar/help/register_shell_menu_shortcuts", 0, _op.register_shell_menu_shortcuts};
			{ nil, 0, 0 },
			{ "menu_bar/help/homepage", 0, _op.open_homepage };
			{ "menu_bar/help/about", icon("about"), _op.show_about };
		}
	};
};

function make_menu( menu, menu_info, menu_pos )
	local menu_idx = -1;
	for k, v in pairs( menu_info ) do
		menu_idx = menu_idx + 1;
		if v[1] == nil then
			menu.insert_line( -1, v[3], true );
		else
			local sc_name = "";
			local sc = short_cuts[v[3]];
			if type(sc) == "table" and type(sc[1]) == "table" then
				-- 更新菜单项关联功能信息
				-- 把当前菜单项关联到功能上
				-- 以便在修改这个功能对应的快捷键时
				-- 可以同步更新菜单的显示
				if type(sc["menu_items"]) ~= "table" then
					sc["menu_items"] = {};
				end;
				local mi = {table.unpack(menu_pos)};
				table.insert( mi, v[3] );
				mi[1] = v[1];
				sc["menu_items"][menu_pos[1]] = mi;

				-- 根据功能的快捷键生成菜单显示的快捷键信息
				local _sc = {table.unpack(sc[1])};
				table.remove( _sc );
				for i,k in pairs(_sc) do
					if sc_name == "" then
						sc_name = "\t";
						sc_name = sc_name..kname( k );
					else
						sc_name = sc_name..","..kname( k );
					end;
				end;
			end;
			menu.insert_item( -1, LANG(v[1])..sc_name, v[3], true );
			if v[2] ~= 0 then
				menu.set_icon( v[3], v[2], false );
			end;
			if v[4] == false then
				menu.enable_item( v[3], false, false );
			end;
			if v[5] == false then
				menu.show_item( v[3], false, false );
			end;
			if type(v.sub_menu) == "table" then
				local mp ={table.unpack(menu_pos)};
				table.insert( mp ,v[3] );
				make_menu( menu.sub_menu( menu_idx, true ), v.sub_menu, mp );
			end;
			if v.always_send_command then
				menu.set_always_send_command( v[3], true, false );
			end;
		end;
	end;
end;

function make_menus()
	local bar = menu_bar;
	for k, v in pairs( _menu_bar ) do
		local sm = bar.sub_menu( v[2], false );
		if sm ~= nil then
			bar.remove_item( v[2], false );
		end;
		bar.insert_item( -1, LANG(v[1]), v[2], true );
		sm = bar.sub_menu( v[2], false );
		if v[3] == false then
			bar.show_item( v[2], false, false );
		end;
		if v.sub_menu ~= nil then
			make_menu( sm, v.sub_menu, {"menu bar",v[2]} );
		end;
	end;
	if not edx.is_frameless then
		bar.set_align( 0x8888888, false, false );
	end;
	local format_menu = edx.get_object("menu:doc_format");
	format_menu.reset();
	make_menu(format_menu, _format_menu, {"format popup"});

	local popup_menu = edx.get_object("menu:popup");
	popup_menu.reset();
	make_menu(popup_menu, _popup_menu, {"text popup"});

	local syntax_menu = edx.get_object("menu:syntax");
	syntax_menu.reset();
	make_menu(syntax_menu, _syntax_menu, {"syntax popup"});

	local line_format_menu = edx.get_object("menu:line_format");
	line_format_menu.reset();
	make_menu(line_format_menu, _line_format_menu, {"line format popup"});

	local tab_menu = edx.get_object("menu:doc_tab");
	tab_menu.reset();
	make_menu(tab_menu, _tab_menu, {"tab popup"});
	
	edx.xws_mgr.popup_menu.reset();
	make_menu(edx.xws_mgr.popup_menu, _solution_menu, {"solution popup"});
	
	local git_menu = edx.get_object("menu:git");
	git_menu.reset();
	make_menu(git_menu, _git_menu, {"git popup"});
end;

function get_short_cuts_name(sc_ope)
	local sc_item = short_cuts[sc_ope];
	if type(sc_item) == "table" and type(sc_item["menu_items"]) == "table" then
		local old_sc = sc_item[1];
		local _sc = {table.unpack(old_sc)};
		table.remove(_sc, #_sc);
		local sc_name = ""; 
		for i,k in pairs(_sc) do
			if sc_name == "" then
				sc_name = "\t";
				sc_name = sc_name..kname( k );
			else
				sc_name = sc_name..","..kname( k );
			end;
		end;
		return sc_name;
	end;
	return "";
end;

function update_short_cuts( sc_ope, sc )
	local sc_item = short_cuts[sc[1]];
	if type(sc_item) == "table" and type(sc_item["menu_items"]) == "table" then
		local old_sc = sc_item[1];
		local old_sc_ope = table.remove( old_sc );
		table.insert( old_sc, 1, _op.none );
		-- 注销旧的short cuts
		edx.register_short_cuts( old_sc_ope, old_sc );
		-- 生成新快捷键的菜单文本
		local _sc = {table.unpack(sc)};
		table.remove( _sc, 1 );
		local sc_name = ""; 
		for i,k in pairs(_sc) do
			if sc_name == "" then
				sc_name = "\t";
				sc_name = sc_name..kname( k );
			else
				sc_name = sc_name..","..kname( k );
			end;
		end;
		-- 更新所有关联菜单
		for menu, item_ids in pairs(sc_item["menu_items"]) do
			if menu == "menu bar" then
				menu = menu_bar;
			elseif menu == "text popup" then
				menu = edx.get_object("menu:popup");
			else
				menu = nil;
			end;
			if menu == nil then
				break;
			end;
			local idx;
			local len = sizeof(item_ids);
			for idx=2,len-1, 1 do
				menu = menu.sub_menu( item_ids[idx], false );
			end;
			menu.set_text( item_ids[len], LANG(item_ids[1])..sc_name, false );
		end;
	end;
	local new_sc = {table.unpack(sc)};
	table.remove( new_sc, 1 );
	table.insert( new_sc, sc_ope );
	if short_cuts[sc[1]] == nil then
		short_cuts[sc[1]] = {};
	end;
	short_cuts[sc[1]][1] = new_sc;
	edx.register_short_cuts( sc_ope, sc );
end;

-- 注册默认快捷键
register_short_cuts();
-- 注册默认菜单
make_menus();

menu_bar.checked_icon = icon("checked");

menu_bar.show_project_menu = function()
	local file_menu = menu_bar.sub_menu(0x8000001, false);
	file_menu:show_item(_op.close_solution, true, false);
	-- menu_bar.show_item( 0x8000003, true, false );
end;

menu_bar.hide_project_menu = function()
	local file_menu = menu_bar.sub_menu(0x8000001, false);
	file_menu:show_item(_op.close_solution, false, false);
	menu_bar.show_item( 0x8000003, false, false );
end;

menu_bar.show_cmake_menu = function()
	local file_menu = menu_bar.sub_menu(0x8000001, false);
	file_menu:show_item(_op.close_solution, true, false);
	menu_bar.show_item( 0xA000001, true, false );
end;

menu_bar.hide_cmake_menu = function()
	local file_menu = menu_bar.sub_menu(0x8000001, false);
	file_menu:show_item(_op.close_solution, false, false);
	menu_bar.show_item( 0xA000001, false, false );
end;

local cmake_set_default_target = function(cmake_menu, target_menu, target_id, item)
	menu_bar.__cmake_def_target = item;
	cmake_menu.set_text(_op.build_target, LANG("menu_bar/cmake/build").." " .. item.name..get_short_cuts_name(_op.build_target), false);
	cmake_menu.set_text(_op.rebuild_target, LANG("menu_bar/cmake/rebuild").." " .. item.name, false);
	cmake_menu.set_text(0xA100003, LANG("menu_bar/cmake/targets").."(" .. item.name .. ")", false);
	target_menu.set_icon(target_id, menu_bar.checked_icon, false);
end;

menu_bar.update_cmake_target = function(targets)
	menu_bar.__cmake_targets = targets;
	local cmake_menu = menu_bar.sub_menu( 0xA000001, false );
	local target_menu = cmake_menu.sub_menu(0xA100003,false);
	-- clean up old target
	local default_target = menu_bar.__cmake_def_target and menu_bar.__cmake_def_target.name;
	local first_target = nil;
	target_menu.reset();
	local no_default_target = true;
	local has_install = false;
	for i,item in ipairs(targets) do
		if menu_bar._cmake_target_filter and menu_bar._cmake_target_filter(item) then
			
		elseif item.name == "install" or item.name == "install/strip" then
			has_install = true;
		else
			local target_id = CMAKE_TARGETS_ID_BASE+i;
			target_menu.insert_item(i, item.name, target_id, true);
			if item.name ~= "install" and item.name ~= "test" then
				if default_target == nil then
					default_target = item.name;
				end;
				if first_target == nil then
					first_target = { target_id, item };
				end;
			end ;
			if default_target == item.name then
				cmake_set_default_target(cmake_menu, target_menu, target_id, item);
				no_default_target = false;
			end;
		end;
	end;
	if no_default_target and first_target then
		-- select the first target
		local old_default_target = menu_bar.__cmake_def_target;
		cmake_set_default_target(cmake_menu, target_menu, first_target[1], first_target[2]);
		if old_default_target then
			local message =
			string.format(LANG("notify/old_target_not_found"), old_default_target.name) .. "\n" ..
			string.format(LANG("notify/new_target_selected"), first_target[2].name);
			show_notify(message);
		end;
	end;
	cmake_menu.show_item(_op.cmake_install, has_install, false);
end;

menu_bar.set_cmake_default_target = function(target_id)
	local cmake_menu = menu_bar.sub_menu( 0xA000001, false );
	local target_menu = cmake_menu.sub_menu( 0xA100003, false );
	local old_target = menu_bar.__cmake_def_target;

	if type(target_id) == "string" then
		for i,item in ipairs(menu_bar.__cmake_targets) do
			if item.name == target_id then
				target_id = i+CMAKE_TARGETS_ID_BASE;
				break;
			end;
		end;
		if type(target_id) == "string" then
			return false;
		end;
	end;

	for i,item in ipairs(menu_bar.__cmake_targets) do
		if (CMAKE_TARGETS_ID_BASE+i == target_id) then
			cmake_set_default_target(cmake_menu, target_menu, target_id, item);
		else
			target_menu.set_icon(CMAKE_TARGETS_ID_BASE+i, 0, false);
		end
	end;
	return old_target ~= menu_bar.__cmake_def_target;
end;

menu_bar.get_cmake_default_target = function()
	return menu_bar.__cmake_def_target;
end;

local cmake_item_map = {
	["config"] = {
		id = 0xA100001;
		lang = "menu_bar/cmake/configuration";
		base_id = CMAKE_CONFIG_ID_BASE;
	};
	["toolset"] = {
		id = 0xA100002;
		lang = "menu_bar/cmake/toolsets";
		base_id = CMAKE_TOOLSET_ID_BASE;
	};
	["targets"] = {
		id = 0xA100003;
		lang = "menu_bar/cmake/targets";
		base_id = CMAKE_TARGETS_ID_BASE;
	};
	["serial_ports"] = {
		id = 0xA100004;
		lang = "menu_bar/cmake/serial_ports";
		base_id = CMAKE_SERIAL_PORTS_ID_BASE;
	};
	["serial_baud"] = {
		id = 0xA100008;
		lang = "menu_bar/cmake/serial_baud";
		base_id = CMAKE_SERIAL_BUAD_ID_BASE;
	};
	["cpus"] = {
		id = 0xA100005;
		lang = "menu_bar/cmake/cpus";
		base_id = CMAKE_CPU_TYPES_ID_BASE;
	};
	["boards"] = {
		id = 0xA100006;
		lang = "menu_bar/cmake/boards";
		base_id = CMAKE_BOARD_TYPES_ID_BASE;
	};
	["debug_adapters"] = {
		id = 0xA100007;
		lang = "menu_bar/cmake/debug_adapters";
		base_id = CMAKE_DEBUG_ADAPTERS_ID_BASE;
	};
};

menu_bar.set_cmake_text = function(text)
	menu_bar.set_text(0xA000001, text, false);
end;

menu_bar.show_cmake_items = function(...)
	local cmake_menu = menu_bar.sub_menu( 0xA000001, false );
	for idx, val in ipairs({...}) do
		local id = cmake_item_map[val].id;
		if id then
			cmake_menu.show_item(id, true, false);
		end;
	end;
end;

menu_bar.hide_cmake_items = function(...)
	local cmake_menu = menu_bar.sub_menu( 0xA000001, false );
	for idx, val in ipairs({...}) do
		local id = cmake_item_map[val].id;
		if id then
			cmake_menu.show_item(id, false, false);
		end;
	end;
end;

local function __cmake_get_impl(cmake_menu, ctx, by_item)
	if ctx.item_id then
		if by_item then
			return ctx["items"][ctx.item_key].data;
		end;
		return ctx.item_key;
	end;
	return nil;
end;

local function __cmake_set_impl(cmake_menu, ctx, item_id)
	local item = nil;
	if type(item_id) == "string" then
		item = ctx["items"][item_id];
	else
		for key, obj in pairs(ctx["items"]) do
			if obj.id == item_id then
				item = obj;
				break;
			end;
		end;
	end;
	if item == nil then
		return false;
	end;
	item_id = item.id;
	local old_id = ctx.item_id;
	ctx.item_id = item_id;
	ctx.item_key = item.key;
	local sub_menu = cmake_menu.sub_menu(ctx.id, false);
	if old_id ~= item_id then
		sub_menu.set_icon(old_id, 0, false);
	end;
	if ctx.lang then
		local item_name = LANG(ctx.lang);
		cmake_menu.set_text(ctx.id, item_name .. "("..item.key..")", false);
	end;
	sub_menu.set_icon(item_id, menu_bar.checked_icon, false);
	return old_id ~= item_id;
end;

local function __cmake_update_impl(cmake_menu, ctx, item_data_set, def_item, make_item)
	if item_data_set == nil then
		item_data_set = ctx.data_set;
	else
		ctx.data_set = item_data_set;
	end;
	local base_id = ctx.base_id;
	if type(item_data_set) == "function" then
		item_data_set = item_data_set();
	end;
	if make_item == nil and ctx.make_item ~= nil then
		make_item = ctx.make_item;
	else
		if make_item == nil then
			if type(item_data_set[1]) == "table" then
				make_item = function(val) return val[1], table.concat(val, "\t"); end;
			else
				make_item = function(val) return val, val; end;
			end;
		end;
		ctx.make_item = make_item;
	end;
	local sub_menu = cmake_menu.sub_menu(ctx.id, false);
	local old_item = (ctx.item_id and sub_menu.get_text(ctx.item_id, false)) or def_item;
	sub_menu:reset();
	local new_items = {};
	local item_selected = nil;
	for idx, val in ipairs(item_data_set) do
		local key, item_text = make_item(val);
		local item_id = base_id + idx - 1;
		new_items[key] = {
			id = item_id;
			key = key;
			["data"] = val;
		};
		sub_menu:insert_item(-1, item_text, item_id, true);
		if old_item == nil or old_item == key then
			old_item = item_id;
			sub_menu.set_icon(item_id, menu_bar.checked_icon, false);
			item_selected = key;
			ctx.item_id = item_id;
			ctx.item_key = item_selected;
		end;
	end;
	if not item_selected and #item_data_set > 0 then
		sub_menu.set_icon(base_id, menu_bar.checked_icon, false);
		item_selected = make_item(item_data_set[1]);
		ctx.item_id = base_id;
		ctx.item_key = item_selected;
	end;
	if ctx.lang then
		local text = LANG(ctx.lang);
		if item_selected then
			text = text.."("..item_selected..")";
		end;
		cmake_menu.set_text(ctx.id, text, false);
	end;
	ctx["items"] = new_items;
end;

local function make_checkable_submenu(menu_name, item_key)
	local _store = {
		id = cmake_item_map[item_key].id;
		lang = cmake_item_map[item_key].lang;
		base_id = cmake_item_map[item_key].base_id;
	};
	local cmake_menu = menu_bar.sub_menu(0xA000001, false);
	
	menu_bar["get_cmake_"..menu_name] = function(by_item)
		return __cmake_get_impl(cmake_menu, _store, by_item);
	end;

	menu_bar["set_cmake_"..menu_name] = function(item_id)
		return __cmake_set_impl(cmake_menu, _store, item_id);
	end;

	menu_bar["update_cmake_"..menu_name] = function(item_data_set, def_item, make_item)
		return __cmake_update_impl(cmake_menu, _store, item_data_set, def_item, make_item);
	end;
end;

make_checkable_submenu("config", "config");
make_checkable_submenu("serial_port", "serial_ports");
make_checkable_submenu("serial_baud", "serial_baud");
make_checkable_submenu("cpu", "cpus");
make_checkable_submenu("board", "boards");
make_checkable_submenu("debug_adapter", "debug_adapters");
make_checkable_submenu("toolset", "toolset");

menu_bar.update_cmake_config({
	{"Debug"},
	{"Release"},
	{"RelWithDebInfo"},
	{"MinSizeRel"},
});

menu_bar.disable_cmake_menu_items = function()
	local cmake_menu = menu_bar.sub_menu( 0xA000001, false );
	local idx = 0;
	while true do
		if cmake_menu.enable_item(idx, false, true) == false then
			break;
		end;
		idx = idx + 1;
	end;
end;

menu_bar.enable_cmake_menu_items = function()
	local cmake_menu = menu_bar.sub_menu( 0xA000001, false );
	local idx = 0;
	while true do
		if cmake_menu.enable_item(idx, true, true) == false then
			break;
		end;
		idx = idx + 1;
	end;
end;

menu_bar.show_debug_menu = function()
	menu_bar.show_item( 0xB000001, true, false );
end;

menu_bar.hide_debug_menu = function()
	menu_bar.show_item( 0xB000001, false, false );
end;

menu_bar.switch_debug_menu = function(self, status)
	if self.__last_debug_menu_status == status then
		return;
	end;
	self.__last_debug_menu_status = status;
	local debug_menu = menu_bar.sub_menu( 0xB000001, false );
	if status == "debugging" then
		debug_menu.set_text(_op.debug_start, LANG("menu_bar/debug/continue")..get_short_cuts_name(_op.debug_start), false);
		debug_menu.enable_item(_op.debug_start, false, false);
		debug_menu.enable_item(_op.build_and_run, false, false);
		debug_menu.enable_item(_op.debug_terminate, true, false);
		debug_menu.enable_item(_op.debug_break, true, false);
		debug_menu.enable_item(_op.debug_step_over, false, false);
		debug_menu.enable_item(_op.debug_step_in, false, false);
		debug_menu.enable_item(_op.debug_step_out, false, false);
		debug_menu.enable_item(_op.debug_jump_to, false, false);
	elseif status == "paused" then
		debug_menu.enable_item(_op.debug_start, true, false);
		debug_menu.enable_item(_op.debug_step_over, true, false);
		debug_menu.enable_item(_op.debug_step_in, true, false);
		debug_menu.enable_item(_op.debug_step_out, true, false);
		debug_menu.enable_item(_op.debug_jump_to, true, false);
	else
		debug_menu.set_text(_op.debug_start, LANG("menu_bar/debug/start_debug")..get_short_cuts_name(_op.debug_start), false);
		debug_menu.enable_item(_op.debug_start, true, false);
		debug_menu.enable_item(_op.build_and_run, true, false);
		debug_menu.enable_item(_op.debug_terminate, false, false);
		debug_menu.enable_item(_op.debug_break, false, false);
		debug_menu.enable_item(_op.debug_step_over, true, false);
		debug_menu.enable_item(_op.debug_step_in, true, false);
		debug_menu.enable_item(_op.debug_step_out, false, false);
		debug_menu.enable_item(_op.debug_jump_to, false, false);
	end;
end;

menu_bar.hide_cmake_items("serial_ports", "serial_baud", "debug_adapters", "cpus", "boards");
menu_bar.show_cmake_items("config", "toolset");

function edx:register_shell_menu()
	local app_path = self.app_path;
	local edx_path = make_path(app_path, "edx.exe");
	local open_with_edx = LANG("shell/open_with_edx");
	utils:write_reg([[HKCU\SOFTWARE\Classes\*\shell\EDX\]], open_with_edx);
	utils:write_reg([[HKCU\SOFTWARE\Classes\*\shell\EDX\Icon]], edx_path);
	utils:write_reg([[HKCU\SOFTWARE\Classes\*\shell\EDX\command\]], edx_path..[[ "%1"]]);

	utils:write_reg([[HKCU\SOFTWARE\Classes\Directory\shell\EDX\]], open_with_edx);
	utils:write_reg([[HKCU\SOFTWARE\Classes\Directory\shell\EDX\Icon]], edx_path);
	utils:write_reg([[HKCU\SOFTWARE\Classes\Directory\shell\EDX\command\]], edx_path..[[ "%1"]]);
	
	utils:write_reg([[HKCU\SOFTWARE\Classes\Directory\Background\shell\EDX\]], open_with_edx);
	utils:write_reg([[HKCU\SOFTWARE\Classes\Directory\Background\shell\EDX\Icon]], edx_path);
	utils:write_reg([[HKCU\SOFTWARE\Classes\Directory\Background\shell\EDX\command\]], edx_path..[[ "%V"]]);

	local reg_val = utils:read_reg([[HKCU\SOFTWARE\Classes\Directory\Background\shell\EDX\Icon]]);
	if reg_val == edx_path then
		self:alert(LANG("notify/register_shortcuts/success"));
	else
		self:alert(LANG("notify/register_shortcuts/failed"));
	end;
end;
